﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using MemoDb.Tests.Model.Collections;
using NUnit.Framework;

namespace MemoDb.Tests
{
    public class CollectionsUpdateTests
    {
        private Child child1;
        private Child child2;

        [SetUp]
        public void SetUp()
        {
            child1 = new Child
           {
               Id = 1,
               Name = "child 1",
           };

            child2 = new Child
            {
                Id = 2,
                Name = "child 2",
            };
        }

        [Test]
        public void Array()
        {
            Test(new[]
                     {
                         child1,
                         child2
                     }, x => x);
        }

        [Test]
        public void IList()
        {
            Test<IList>(new ArrayList
                            {
                                child1,
                                child2
                            }, x => x.Cast<Child>().ToArray());
        }

        [Test]
        public void GenericIList()
        {
            Test<IList<Child>>(new List<Child>
                            {
                                child1,
                                child2
                            }, x => x.ToArray());
        }

        [Test]
        public void ArrayList()
        {
            Test(new ArrayList
                            {
                                child1,
                                child2
                            }, x => x.Cast<Child>().ToArray());
        }

        [Test]
        public void GenericList()
        {
            Test(new List<Child>
                            {
                                child1,
                                child2
                            }, x => x.ToArray());
        }

        [Test]
        public void EnititySet()
        {
            Test(new EntitySet<Child>
                            {
                                child1,
                                child2
                            }, x => x.ToArray());
        }

        [Test]
        public void IDictionaryValues()
        {
            Test<IDictionary>(new Hashtable
                            {
                                {1,child1},
                                {2,child2}
                            }, x => x.Values.Cast<Child>().ToArray());
        }

        [Test]
        public void IDictionaryGenericValues()
        {
            Test<IDictionary<int, Child>>(new Dictionary<int, Child>
                                              {
                                                  {1, child1},
                                                  {2, child2}
                                              }, x => x.Values.ToArray());
        }
        [Test]
        public void HashtableValues()
        {
            Test(new Hashtable
                            {
                                {1,child1},
                                {2,child2}
                            }, x => x.Values.Cast<Child>().ToArray());
        }

        [Test]
        public void DictionaryGenericValues()
        {
            Test(new Dictionary<int, Child>
                                              {
                                                  {1, child1},
                                                  {2, child2}
                                              }, x => x.Values.ToArray());
        }



        [Test]
        public void IDictionaryKeys()
        {
            Test<IDictionary>(new Hashtable
                            {
                                {child1,1},
                                {child2,2}
                            }, x => x.Keys.Cast<Child>().ToArray());
        }

        [Test]
        public void IDictionaryGenericKeys()
        {
            Test<IDictionary<Child, int>>(new Dictionary<Child, int>
                                              {
                                                  {child1, 1},
                                                  {child2, 2}
                                              }, x => x.Keys.ToArray());
        }
        [Test]
        public void HashtableKeys()
        {
            Test(new Hashtable
                            {
                                {child1,1},
                                {child2,2}
                            }, x => x.Keys.Cast<Child>().ToArray());
        }

        [Test]
        public void DictionaryGenericKeys()
        {
            Test(new Dictionary<Child, int>
                                              {
                                                  {child1, 1},
                                                  {child2, 2}
                                              }, x => x.Keys.ToArray());
        }


        private void Test<T>(T children, Func<T, Child[]> convertToArray)
        {
            var memo = new Memo()
                            .Map<Child>()
                            .Map<Parent<T>>();

            var parent = new Parent<T>
            {
                Id = 1,
                Name = "parent",
            };

            using (var s = memo.CreateSession())
            {
                s.Insert(parent);
                s.Insert(child1);
                s.Insert(child2);
                s.Flush();
                parent.Children = children;
                s.Flush();
            }

            Parent<T> parent2;
            using (var s = memo.CreateSession())
            {
                parent2 = s.GetById<Parent<T>>(parent.Id);
                var items = convertToArray(parent2.Children);

                Assert.AreEqual(2, items.Length);
                Assert.That(items.Any(x => x.Name == "child 1"));
                Assert.That(items.Any(x => x.Name == "child 2"));
                Assert.That(items.All(x => x != child1 && x != child2));
            }
        }
    }
}